/** AJAX工具和中间件，封装fetch操作 */
import {
    CONTENT_TYPE,
    parseResponse,
    checkStatus
} from './http';

const credentials = 'same-origin';
const JSON_TYPE = 'application/json';
const TYPE = Symbol('AJAX');

// 后台API URI前端
let _api_prefix = '/api';
// token获取方法
let _get_token;

/**
 * 设置后台API访问前缀，会自动为所有请求添加此前缀
 * @param api_prefix API前缀（如/api）
 */
export function setApiPrefix(api_prefix) {
    _api_prefix = api_prefix || '';
}

/**
 * 设置获取token的方法，以便AJAX请求时添加到header
 * @param token_getter token获取方法
 */
export function setToken(token_getter) {
    _get_token = token_getter;
    if (typeof token_getter === 'string') {
        _get_token = () => token_getter;
    }
}

function ajaxFetch(url, opt) {
    return fetch(url, opt)
        .then(parseResponse)
        .then(checkStatus);
}

function ajaxAction(url, opt) {
    return {
        type: TYPE,
        payload: {url, opt}
    };
}

/**
 * AJAX中间件，根据action类型调用fetch
 */
/* eslint no-unused-vars: 0 */
export default store => next => action => {
    if (action.type === TYPE) {
        const {url, opt} = action.payload;
        return ajaxFetch(url, opt);
    }
    return next(action);
};

/**
 * 执行AJAX操作
 * @param url 请求路径
 * @param opt 请求选项（fetch的）
 * @param direct 是否直接调用fetch
 * @returns {Promise|action} 直接调用fetch返回Promise，否则通过返回action间接调用，
 */
function ajax(url, opt, direct) {
    const api = (direct === null) ? url : _api_prefix + url;
    const act = (typeof direct === 'boolean' && direct) ? ajaxFetch : ajaxAction;
    const token = _get_token ? _get_token(true) : undefined;
    if (token) {
        // 添加token头
        if (!opt.headers) {
            opt.headers = {};
        }
        opt.headers.Authorization = token;
    }
    return act(api, {credentials, ...opt});
}

export function get(url, direct) {
    return ajax(url, {}, direct);
}

export function post(url, body, direct) {
    return ajax(url, {
        method: 'post',
        headers: {
            [CONTENT_TYPE]: JSON_TYPE
        },
        body: JSON.stringify(body)
    }, direct);
}

export function put(url, body, direct) {
    return ajax(url, {
        method: 'put',
        headers: {
            [CONTENT_TYPE]: JSON_TYPE
        },
        body: JSON.stringify(body)
    }, direct);
}

export function del(url, direct) {
    return ajax(url, {
        method: 'delete'
    }, direct);
}
